package com.wmd.core.operation;

import com.baomidou.mybatisplus.annotation.TableName;
import com.wmd.core.enums.QueryTypeEnum;
import com.wmd.core.function.SFunction;
import com.wmd.core.util.*;
import lombok.var;

import java.lang.reflect.Field;
import java.util.*;

/**
 * description:拼接Sql工具类
 * author: luyincheng
 * date: 2021/1/18 10:56
 */
public class UnionCriteria {

    public static String Table_Name_prefix = "t_";

    public static String DBType = "Mysql";

    public static String serialVersionUID="serialVersionUID";

    protected String orderByClause;

    protected String groupByClause;
    protected boolean distinct;

    protected List<Criteria> oredCriteria;

    protected Integer limitStart;

    protected Integer limitEnd;

    protected FromClause fromClause;

    protected String resultColumn;

    protected boolean count;

    public boolean isCount() {
        return count;
    }

    public void setCount(boolean count) {
        this.count = count;
    }

    public String getResultColumn() {
        return resultColumn;
    }

    public UnionCriteria setResultColumn(String resultColumn) {
        this.resultColumn = resultColumn;
        return this;
    }

    public UnionCriteria() {
        oredCriteria = new ArrayList<Criteria>();
    }

    public void setOrderByClause(String orderByClause) {
        this.orderByClause = orderByClause;
    }

    public String getOrderByClause() {
        return orderByClause;
    }

    public void setDistinct(boolean distinct) {
        this.distinct = distinct;
    }

    public boolean isDistinct() {
        return distinct;
    }

    public List<Criteria> getOredCriteria() {
        return oredCriteria;
    }

    public String getGroupByClause() {
        return groupByClause;
    }

    public void setGroupByClause(String groupByClause) {
        this.groupByClause = groupByClause;
    }

    public void or(Criteria criteria) {
        oredCriteria.add(criteria);
    }

    public Criteria or() {
        Criteria criteria = createCriteriaInternal();
        oredCriteria.add(criteria);
        return criteria;
    }

    public Criteria createCriteria() {
        Criteria criteria = createCriteriaInternal();
        if (oredCriteria.size() == 0) {
            oredCriteria.add(criteria);
        }
        return criteria;
    }

    /**
     * @description:通过class创建from语句
     * @author: luyincheng
     * @date: 2021/1/21 9:48
     * @param masterTable 主表名称（数据库名称）
     * @param masterTableClass 主表对应entity class
     * @return: com.wmd.core.operation.UnionCriteria.FromClause
     */
    public FromClause createFromClauseByClass(String masterTable, Class<?> masterTableClass) {
        String masterTableAlias = GetTableNameFromClass(masterTableClass);
        this.fromClause = new FromClause(masterTable, masterTableAlias.toUpperCase(), masterTableClass);
        return this.fromClause;
    }
    /**
     * @description:通过class创建from语句
     * @author: luyincheng
     * @date: 2021/1/21 9:48
     * @param masterTableClass 主表对应entity class
     * @return: com.wmd.core.operation.UnionCriteria.FromClause
     */
    public FromClause createFromClauseByClass(Class<?> masterTableClass) {
        return createFromClauseByClass(masterTableClass,true,true);
    }
    public FromClause createFromClauseByClassNoneResult(Class<?> masterTableClass,boolean IsResultTable) {
        return createFromClauseByClass(masterTableClass,IsResultTable,true);
    }
    /**
     * @description:
     * @author: luyincheng
     * @date: 2021/1/25 10:08
     * @param masterTableClass 主表对应entity class
     * @param containPrefix 返回列是否包含前缀
     * @return: com.wmd.core.operation.UnionCriteria.FromClause
     */
    public FromClause createFromClauseByClass(Class<?> masterTableClass,boolean IsResultTable,boolean containPrefix) {
        String DB_TableName = GetTableNameFromClass(masterTableClass).toUpperCase();
        this.fromClause = new FromClause(DB_TableName, DB_TableName.toUpperCase(), masterTableClass,IsResultTable,containPrefix);
        return this.fromClause;
    }

	public FromClause createFromClauseByClass(Class<?> masterTableClass,UnionCriteria subQueryCriteria) {
        String DB_TableName = GetTableNameFromClass(masterTableClass).toUpperCase();
		this.fromClause = new FromClause(subQueryCriteria, DB_TableName.toUpperCase(), masterTableClass);
		return this.fromClause;
	}
	public FromClause createFromClauseByClass(Class<?> masterTableClass,UnionCriteria subQueryCriteria, String masterTableAlias) {
//		String DB_TableName = UnionCriteria.Table_Name_prefix + HumpTransform.humpToLine2(masterTableClass.getSimpleName());
		this.fromClause = new FromClause(subQueryCriteria, masterTableAlias, masterTableClass);
		return this.fromClause;
	}

    public FromClause createFromClause(String masterTable, String masterTableAlias) {
        this.fromClause = new FromClause(masterTable, masterTableAlias);
        return this.fromClause;
    }

    public FromClause createFromClauseByClass(String masterTable, String masterTableAlias, Class<?> masterTableClass) {
        this.fromClause = new FromClause(masterTable, masterTableAlias, masterTableClass);
        return this.fromClause;
    }


    public FromClause createFromClause(UnionCriteria subQueryCriteria, String masterTableAlias) {
        this.fromClause = new FromClause(subQueryCriteria, masterTableAlias);
        return this.fromClause;
    }

    public FromClause createFromClause(UnionCriteria subQueryCriteria, String masterTableAlias, Class<?> masterTableClass) {
        this.fromClause = new FromClause(subQueryCriteria, masterTableAlias, masterTableClass);
        return this.fromClause;
    }


    protected Criteria createCriteriaInternal() {
        Criteria criteria = new Criteria();
        return criteria;
    }

    public void clear() {
        oredCriteria.clear();
        orderByClause = null;
        groupByClause = null;
        distinct = false;
        fromClause = null;
        limitStart = 0;
        limitEnd = 0;
        resultColumn = null;
    }

    public void clearCriteria() {
        oredCriteria.clear();

    }

    public void setLimitStart(Integer limitStart) {
        this.limitStart = limitStart;
    }

    public Integer getLimitStart() {
        return limitStart;
    }

    public void setLimitEnd(Integer limitEnd) {
        this.limitEnd = limitEnd;
    }

    public Integer getLimitEnd() {
        return limitEnd;
    }

    public UnionCriteria isValid() {
        List<Criteria> cs = this.oredCriteria;
        if (cs.isEmpty()) {
            return null;
        }
        for (int i = 0; i < cs.size(); i++) {
            if (cs.get(i).isValid()) {
                return (UnionCriteria) this;
            }
            ;
        }
        return null;
    }

    public FromClause getFromClause() {
        return fromClause;
    }

    public void setFromClause(FromClause fromClause) {
        this.fromClause = fromClause;
    }
    /**
     * @description:计算生成Group by语句
     * @author: luyincheng
     * @date: 2021/1/21 9:49
     * @param
     * @return: java.lang.String
     */
    public String calculateGroupByClause() {
        StringBuilder sb = new StringBuilder();
        if (this.fromClause.columns == null) {
            return null;
        }
        this.fromClause.columns.forEach((k, v) -> {
			String[] value=(String[])v;
            String finalFieldName = StringUtil.isEmpty(value[0]) ? k.toString() : value[0] + "." + k;
//            if (k.equals(v[1])) {
//                finalFieldName = v[0] + "." + k;
//            } else {
//                finalFieldName = v[0] + "." + v[1];
//
//            }
            if (sb.length() > 0) {
                sb.append("," + finalFieldName);
            } else {
                sb.append(finalFieldName);
            }
        });
        this.groupByClause = sb.toString();
        return this.groupByClause;
    }

    public static String GetTableNameFromClass(Class<?> c) {
        var tablename=c.getAnnotation(TableName.class);
        if(tablename!=null){
            return tablename.value();
        }
        return GetTableNameFromClassSimpleName(c.getSimpleName());
    }
    public static String GetTableNameFromClassSimpleName(String simpleName) {
        String DB_tableName = UnionCriteria.Table_Name_prefix + HumpTransform.humpToLine2(simpleName);
        return DB_tableName;
    }

    public String GeneratorSql(){
        StringBuffer sql=new StringBuffer();
        sql.append("select ");
        if(this.distinct){
            sql.append("distinct 'true' as QUERYID,");
        }
        if(!StringUtil.isEmpty(resultColumn)){
            sql.append(this.resultColumn);
        }else{
            if(StringUtil.isEmpty(this.fromClause.masterTableAlias)){
                sql.append("  "+this.fromClause.masterTable+".*");
            }else {
                sql.append("  "+this.fromClause.masterTableAlias+".*");
            }
        }
        sql.append(GenerateCriteriaFromClause());
        sql.append(GenerateCriteriaWhereClause());
        if(!StringUtil.isEmpty(this.groupByClause)){
            sql.append(" group by "+this.groupByClause);
        }
        if(!StringUtil.isEmpty(this.orderByClause)){
            sql.append(" order by "+this.orderByClause);
        }
        return sql.toString();
    }
    public String GenerateCriteriaFromClause(){
        StringBuffer sql=new StringBuffer();
        if(this.fromClause!=null){
            sql.append(" from ");
            if(this.fromClause.isSubQuery){
                sql.append(" ("+this.fromClause.subQueryCriteria.GeneratorSql()+") ");
                sql.append(this.fromClause.masterTableAlias);
            }else{
                sql.append(" ");
                sql.append(this.fromClause.masterTable);
                sql.append(" ");
                sql.append(this.fromClause.masterTableAlias);
                this.fromClause.joinTables.forEach(j->{
                    if(j.isSubQuery){
                        sql.append(" ");
                        sql.append(j.joinType);
                        sql.append(" ("+j.subQueryCriteria.GeneratorSql()+") ");
                        sql.append(j.tableAlias);
                        sql.append(" on ");
                        sql.append(j.condition);
                    }else{
                        sql.append(" ");
                        sql.append(j.joinType);
                        sql.append(" ");
                        sql.append(j.tableName);
                        sql.append(" ");
                        sql.append(j.tableAlias);
                        sql.append(" on ");
                        sql.append(j.condition);
                    }
                });
            }
        }
        return sql.toString();
    }

    public String GenerateCriteriaWhereClause() {
        if (this.oredCriteria.isEmpty()) {
            return "";
        } else {
            StringBuilder sb = new StringBuilder();
            sb.append(" where ");
            for (int i = 0; i < this.oredCriteria.size(); i++) {
                if (i > 0) {
                    sb.append(" or ");
                }
                if (this.oredCriteria.get(i).isValid()) {
                    sb.append(" ( ");
                    List<Criterion> criterions = this.oredCriteria.get(i).getCriteria();
                    for (int j = 0; j < criterions.size(); j++) {
                        if (j > 0) {
                            sb.append(" and ");
                        }
                        Criterion criterion = criterions.get(j);
                        if (criterion.noValue) {
                            sb.append(criterion.getCondition());
                        } else if (criterion.singleValue) {
                            sb.append(criterion.getCondition() + " '" + criterion.getValue() + "'");
                        } else if (criterion.betweenValue) {
                            sb.append(criterion.getCondition() + " '" + criterion.getValue() + "' and '" + criterion.getSecondValue() + "'");
                        } else if (criterion.listValue) {
                            sb.append(criterion.getCondition() + " ");
                            List<?> list = (List<?>) criterion.getValue();
                            StringBuilder sbtemp = new StringBuilder();
                            sbtemp.append(" ( ");
                            list.forEach(l -> {
                                sbtemp.append("'" + l + "',");
                            });
                            sbtemp.substring(0, sbtemp.length() - 1);
                            sbtemp.append(" ) ");
                            sb.append(sbtemp);
                        }
                    }
                    sb.append(" ) ");
                }
            }
            String whereClause=sb.toString();
            if("where".equals(whereClause.trim())){
                return "";
            }else{
                return whereClause;
            }
        }
    }
    public static String GetConditionType(String STYPE){
        QueryTypeEnum e=QueryTypeEnum.valueOf(STYPE);
        return GetConditionType(e);
    }
    public static String GetConditionType(QueryTypeEnum queryTypeEnum){
        String conditionType="=";
        switch (queryTypeEnum) {
            case Like:
                conditionType = " like ";
                break;
            case Equal:
                conditionType = "=";
                break;
            case Greater:
                conditionType = ">";
                break;
            case GreaterEqual:
                conditionType = ">=";
                break;
            case Less:
                conditionType = "<";
                break;
            case LessEqual:
                conditionType = "<=";
                break;
            case NotEqual:
                conditionType = "<>";
                break;
            case In:
                conditionType = " in ";
                break;
            case Between:
                conditionType = " between ";
                break;
            default:
                conditionType = "=";
                break;
        }
        return conditionType;
    }

    public Criteria calculateCrCriteria(Map<String, Object> params) {
        return this.calculateCrCriteria(null, params, 0, true);
    }
    public Criteria calculateCrCriteria(String basePackage, Map<String, Object> params, int criteriaIndex) {
        return this.calculateCrCriteria(basePackage, params, criteriaIndex, true);
    }

    public Criteria calculateCrCriteria(String basePackage, Map<String, Object> params, int criteriaIndex,
                                        boolean maintable, Integer... tableindexs) {
        return this.calculateCrCriteria(basePackage, params, criteriaIndex, maintable, false, tableindexs);
    }
    /**
     * @description:计算生成where条件
     * @author: luyincheng
     * @date: 2021/1/21 9:50
     * @param basePackage 反射entity的包名
     * @param params 查询参数，以“表名_属性”格式为key值
     * @param criteriaIndex 添加到查询块的序号
     * @param maintable 是否包含主表
     * @param repeatCr 是否重复查询，即多表存在同名参数情况，第一张表在添加了查询条件后，若为false，则删除key，第二张表不查询改key值
     * @param tableindexs 包含的副表序号集合
     * @return: com.wmd.core.operation.UnionCriteria.Criteria
     */
    public Criteria calculateCrCriteria(String basePackage, Map<String, Object> params, int criteriaIndex,
                                        boolean maintable, boolean repeatCr, Integer... tableindexs) {
        Criteria criteria;
        if (this.oredCriteria.size() == 0) {
            criteria = createCriteriaInternal();
            oredCriteria.add(criteria);
        } else {
            criteria = this.oredCriteria.get(criteriaIndex);
        }
        if (params == null || params.isEmpty()) {
            return criteria;
        }
        List<JoinTable> alltables = new ArrayList<>();
        if (maintable) {
            alltables.add(new JoinTable(this.fromClause.masterTable, this.fromClause.masterTableAlias, "", null,
                    this.fromClause.masterTableClass));
        }

        if (tableindexs == null || tableindexs.length == 0) {
            alltables.addAll(this.fromClause.joinTables);
        } else {
            int tablesize = this.fromClause.joinTables.size();
            if (tablesize > 0) {
                for (int i = 0; i < tableindexs.length; i++) {
                    if (i < tablesize) {
                        alltables.add(this.fromClause.joinTables.get(i));
                    }
                }
            }
        }
        alltables.forEach(j -> {
            Class<?> c=j.getTableClass(basePackage);
            if (c == null) {
                return;
            }

            String tableAlias;
            if (StringUtil.isEmpty(j.getTableAlias())) {
                tableAlias = "";
            } else {
                tableAlias = j.getTableAlias() + ".";
            }
            // System.out.println("class:"+c.getSimpleName());
//			List<Field> fields = new ArrayList<>();
            Class<?> currentClass = c;
            while (currentClass != null) {
                final Field[] declaredFields = currentClass.getDeclaredFields();
                for (final Field field : declaredFields) {
//					fields.add(field);
                    if(field.getName().equals(serialVersionUID)){
                        continue;
                    }
                    String fieldName = field.getName();
                    // System.out.println("class:"+c.getSimpleName()+" field:"+fieldName);
                    Object o = params.get(currentClass.getSimpleName() + "_" + fieldName);
                    String[] ps;
                    if (o instanceof String[]) {
                        ps = (String[]) o;
                    } else {
                        ps = new String[]{o + ""};
                    }
                    // String[] ps = params.get(fieldName);
                    if (ps != null && ps.length > 0 && !ps[0].equals("null")) {

                        String DB_fieldName = HumpTransform.humpToLine2(fieldName);
                        String SType = "Equal";
                        if (params.containsKey(currentClass.getSimpleName() + "_" + fieldName + MybatisPlusUtils.QueryType)) {
                            SType = params.get(currentClass.getSimpleName() + "_" + fieldName + MybatisPlusUtils.QueryType)+"";
                        }
                        String conditionType = GetConditionType(SType);
                        Object conditionValue = ps[0];
                        if("In".equals(SType)){
                            conditionValue = Arrays.asList(ps);
                        }else if("Between".equals(SType)){
                            conditionValue = ps;
                        }
                        if (field.getType().equals(Date.class)) {
                            switch (DBType) {
                                case "Mysql":
                                    criteria.addCriterionSelective(tableAlias + DB_fieldName + conditionType, conditionValue, fieldName);
                                    break;
                                case "Oracle":
                                    criteria.addCriterionSelective("to_char(" + tableAlias + DB_fieldName + ",'"
                                            + TimeTool.simpleDateFormat_8 + "')" + conditionType, conditionValue, fieldName);
                                    break;
                            }
                        } else {
                            criteria.addCriterionSelective(tableAlias + DB_fieldName + conditionType, conditionValue, fieldName);
                        }

                        if (!repeatCr) {
                            params.remove(fieldName);
                        }
                    }

                }
                currentClass = currentClass.getSuperclass();
            }

        });
        return criteria;

    }

    public static class FromClause {
        private List<JoinTable> joinTables;
        private String masterTable;
        private String masterTableAlias;
        private Class<?> masterTableClass;
        private Map<String, String[]> columns;
        private boolean isSubQuery = false;
        private UnionCriteria subQueryCriteria;
        private boolean ContainPrefix=true;
        private boolean IsResultTable=true;



        public boolean isSubQuery() {
            return isSubQuery;
        }

        public void setSubQuery(boolean isSubQuery) {
            this.isSubQuery = isSubQuery;
        }

        public UnionCriteria getSubQueryCriteria() {
            return subQueryCriteria;
        }

        public void setSubQueryCriteria(UnionCriteria subQueryCriteria) {
            this.subQueryCriteria = subQueryCriteria;
        }

        public Map<String, String[]> getColumns() {
            return columns;
        }

        public void setColumns(Map<String, String[]> columns) {
            this.columns = columns;
        }

        /*
         * public getFromClauseString() { StringBuilder sb=new
         * StringBuilder("from"+masterTable); if(isValid()) {
         *
         * } }
         */
        public String calculateResultColuse(String basePackage, boolean mainTable, int... tableIndex) {
            List<JoinTable> alltables = new ArrayList<>();
            if (mainTable) {
                alltables.add(new JoinTable(masterTable, masterTableAlias, "", null, masterTableClass));
            }
            if (joinTables.size() > 0 && tableIndex != null && tableIndex.length > 0) {
                int tableSize = joinTables.size();
                for (int i = 0; i < tableIndex.length; i++) {
                    if (tableIndex[i] >= 0 && tableIndex[i] < tableSize) {
                        alltables.add(joinTables.get(tableIndex[i]));
                    }
                }
            }
            return this.calculateResultColuse(basePackage, alltables);
        }
        public String calculateResultColuse(boolean mainTable, int... tableIndex) {
            return this.calculateResultColuse(null,mainTable, tableIndex);
        }
        public String calculateResultColuse(String basePackage, int startTable, int endTable, boolean mainTable) {
            List<JoinTable> alltables = new ArrayList<>();
            if (mainTable) {
                alltables.add(new JoinTable(masterTable, masterTableAlias, "", null, masterTableClass));
            }
            if (joinTables.size() > 0) {
                if (joinTables.size() < endTable) {
                    endTable = joinTables.size();
                }
                if (startTable < 0) {
                    startTable = 0;
                }
                for (int i = startTable; i < endTable; i++) {
                    alltables.add(joinTables.get(i));
                }

            }
            return this.calculateResultColuse(basePackage, alltables);
        }

        public String calculateResultColuse(String basePackage) {
            return this.calculateResultColuse(basePackage, null);
        }

        public String calculateResultColuse() {
            return this.calculateResultColuse(null);
        }

        public String calculateResultColuse(String basePackage, List<JoinTable> alltables) {
            StringBuilder sb = new StringBuilder();

            columns = new LinkedHashMap<>();

            if (alltables == null) {
                alltables = new ArrayList<>();
                alltables.add(new JoinTable(masterTable, masterTableAlias, "", null, masterTableClass,IsResultTable,ContainPrefix));
                alltables.addAll(joinTables);
            }
            alltables.forEach(j -> {
                if(!j.IsResultTable){
                    return;
                }
                Class<?> c=j.getTableClass(basePackage);
                if (c == null) {
                    return;
                }
//                List<Field> fields = new ArrayList<>();
                Class<?> currentClass = c;
//                String DB_tableName = UnionCriteria.Table_Name_prefix + HumpTransform.humpToLine2(currentClass.getSimpleName());
                String DB_tableName = GetTableNameFromClass(currentClass);
                String prefix;
                if(j.ContainPrefix){
//                    prefix = DB_tableName.toUpperCase()+ "_" ;
                    //返回列去掉前缀同一用驼峰格式
                    prefix = c.getSimpleName()+"_";
                }else {
                    prefix = "" ;
                }

                while (currentClass != null) {
                    final Field[] declaredFields = currentClass.getDeclaredFields();
                    for (final Field field : declaredFields) {
                        if(field.getName().equals(serialVersionUID)){
                            continue;
                        }
                        String fieldName = field.getName();
                        String DB_fieldName = HumpTransform.humpToLine2(fieldName);

                        //默认不自联查表，即表名+列名绝不重复
                        columns.put(HumpTransform.lineToHump(prefix + DB_fieldName), new String[]{j.getTableAlias(), DB_fieldName});

						/*if (columns.get(DB_fieldName) != null) {
                            String prefix = j.getTableName().toUpperCase();
                            columns.put(prefix + "_" + DB_fieldName, new String[]{j.getTableAlias(), DB_fieldName});
                        } else {
                            columns.put(DB_fieldName, new String[]{j.getTableAlias(), DB_fieldName});
                        }*/
                    }
                    currentClass = currentClass.getSuperclass();
                }
            });
            columns.forEach((k, v) -> {

                String finalFieldName;
                //别名为空，不加
                if (StringUtil.isEmpty(v[0])) {
                    finalFieldName = v[1] + " as " + k;
                } else {
                    finalFieldName = v[0] + "." + v[1] + " as " + k;
                }
//                if (k.equals(v[1])) {
//                    finalFieldName = v[0] + "." + k;
//                } else {
//                    if (k.length() > 30) {
//                        finalFieldName = v[0] + "." + v[1] + " as " + v[0] + "_" + v[1];
//                    } else {
//                        finalFieldName = v[0] + "." + v[1] + " as " + k;
//                    }
//                }
                if (sb.length() > 0) {
                    sb.append("," + finalFieldName);
                } else {
                    sb.append(finalFieldName);
                }
            });

            return sb.toString();
        }

        public FromClause(UnionCriteria subQueryCriteria, String masterTableAlias) {
            super();
            this.subQueryCriteria = subQueryCriteria;
            this.masterTableAlias = masterTableAlias != null ? masterTableAlias : "";
            this.isSubQuery = true;
            joinTables = new ArrayList<>();
        }

        public FromClause(UnionCriteria subQueryCriteria, String masterTableAlias, Class<?> masterTableClass) {
            super();
            this.subQueryCriteria = subQueryCriteria;
            this.masterTableAlias = masterTableAlias != null ? masterTableAlias : "";
            this.masterTableClass = masterTableClass;
            this.isSubQuery = true;
            joinTables = new ArrayList<>();
        }

        public FromClause(String masterTable, String masterTableAlias) {
            super();
            this.masterTable = masterTable;
            this.masterTableAlias = masterTableAlias != null ? masterTableAlias : "";
            joinTables = new ArrayList<>();
        }

        public FromClause(String masterTable, String masterTableAlias, Class<?> masterTableClass) {
            super();
            this.masterTable = masterTable;
            this.masterTableAlias = masterTableAlias != null ? masterTableAlias : "";
            this.masterTableClass = masterTableClass;
            joinTables = new ArrayList<>();
        }
        public FromClause(String masterTable, String masterTableAlias, Class<?> masterTableClass,boolean isResultTable, boolean containPrefix) {
            super();
            this.masterTable = masterTable;
            this.masterTableAlias = masterTableAlias != null ? masterTableAlias : "";
            this.masterTableClass = masterTableClass;
            joinTables = new ArrayList<>();
            this.ContainPrefix=containPrefix;
            this.IsResultTable=isResultTable;
        }

        public FromClause(String masterTable) {
            this(masterTable, null);
        }

        public boolean isValid() {
            return joinTables.size() > 0;
        }

        public Class<?> getMasterTableClass() {
            return masterTableClass;
        }

        public void setMasterTableClass(Class<?> masterTableClass) {
            this.masterTableClass = masterTableClass;
        }
        /**
         * @description:通过calss添加连表副表
         * @author: luyincheng
         * @date: 2021/1/21 9:57
         * @param tableClass 表对应entity calss
         * @param tableLeftColumn 连接条件，左表
         * @param tableRightColumn 连接条件，右表
         * @param joinType 连接类型
         * @return: com.wmd.core.operation.UnionCriteria.FromClause
         */
        public<T1,T2> FromClause addJoinTableByClass(Class<?> tableClass, SFunction<T1, ?> tableLeftColumn, SFunction<T2, ?> tableRightColumn, JoinType joinType) {
            addJoinTableByClass(tableClass,tableLeftColumn,tableRightColumn,joinType,true,true);
            return this;
        }
        /**
         * @description:通过calss添加连表副表
         * @author: luyincheng
         * @date: 2021/1/21 9:57
         * @param tableClass 表对应entity calss
         * @param tableLeftColumn 连接条件，左表
         * @param tableRightColumn 连接条件，右表
         * @param isResultTable 是否是返回表
         * @param joinType 连接类型
         * @param containPrefix 返回字段是否包含前缀
         * @return: com.wmd.core.operation.UnionCriteria.FromClause
         */
        public<T1,T2> FromClause addJoinTableByClass(Class<?> tableClass, SFunction<T1, ?> tableLeftColumn, SFunction<T2, ?> tableRightColumn, JoinType joinType,boolean isResultTable,boolean containPrefix) {
            if (tableClass == null || tableLeftColumn == null || tableRightColumn == null || joinType == null) {
                return this;
            }
            java.lang.invoke.SerializedLambda serializedLambdaLeft=SerializedLambdaUtil.getSerializedLambda(tableLeftColumn);
            java.lang.invoke.SerializedLambda serializedLambdaRight=SerializedLambdaUtil.getSerializedLambda(tableRightColumn);
            String leftColumn = GetTableNameFromClassSimpleName(StringUtil.GetLastUrl(serializedLambdaLeft.getImplClass())).toUpperCase()+"."+HumpTransform.humpToLine2(SerializedLambdaUtil.resolveFieldName(serializedLambdaLeft.getImplMethodName()));
            String rightColumn = GetTableNameFromClassSimpleName(StringUtil.GetLastUrl(serializedLambdaRight.getImplClass())).toUpperCase()+"."+HumpTransform.humpToLine2(SerializedLambdaUtil.resolveFieldName(serializedLambdaRight.getImplMethodName()));
            String tableName = GetTableNameFromClass(tableClass).toUpperCase();
            String tableAlias = tableName;
            String condition =  leftColumn + "=" + rightColumn;
            joinTables.add(new JoinTable(tableName, tableAlias, condition, joinType, tableClass,isResultTable,containPrefix));
            return this;
        }
        public FromClause addJoinTableByClass(Class<?> tableClass,String condition, JoinType joinType) {
            if (tableClass == null || StringUtil.isEmpty(condition) || joinType == null) {
                return this;
            }
            String tableName = GetTableNameFromClass(tableClass).toUpperCase();
            String tableAlias = tableName;
            joinTables.add(new JoinTable(tableName, tableAlias, condition, joinType, tableClass));
            return this;
        }
        /**
         * @description:添加子查询连表
         * @author: luyincheng
         * @date: 2021/1/21 9:58
         * @param subQueryCriteria  子查询条件类
         * @param tableClass 子查询返回结果对应 entity class
         * @param tableLeftColumn 连表左 条件
         * @param tableRightColumn 连表右 条件
         * @param joinType 连表类型
         * @return: com.wmd.core.operation.UnionCriteria.FromClause
         */
        public<T1,T2> FromClause addJoinTableByClass(UnionCriteria subQueryCriteria, Class<?> tableClass, SFunction<T1, ?> tableLeftColumn, SFunction<T2, ?> tableRightColumn, JoinType joinType) {
           addJoinTableByClass(subQueryCriteria,tableClass,tableLeftColumn, tableRightColumn,joinType,true, true);
            return this;
        }
        /**
         * @description:添加子查询连表
         * @author: luyincheng
         * @date: 2021/1/21 9:58
         * @param subQueryCriteria  子查询条件类
         * @param tableClass 子查询返回结果对应 entity class
         * @param tableLeftColumn 连表左 条件
         * @param tableRightColumn 连表右 条件
         * @param joinType 连表类型
         * @param containPrefix 返回字段是否包含前缀
         * @return: com.wmd.core.operation.UnionCriteria.FromClause
         */
        public<T1,T2> FromClause addJoinTableByClass(UnionCriteria subQueryCriteria, Class<?> tableClass, SFunction<T1, ?> tableLeftColumn, SFunction<T2, ?> tableRightColumn, JoinType joinType,boolean isResultTable,boolean containPrefix) {
            if (subQueryCriteria == null || tableClass == null || tableLeftColumn == null || tableRightColumn == null || joinType == null) {
                return this;
            }
            java.lang.invoke.SerializedLambda serializedLambdaLeft=SerializedLambdaUtil.getSerializedLambda(tableLeftColumn);
            java.lang.invoke.SerializedLambda serializedLambdaRight=SerializedLambdaUtil.getSerializedLambda(tableRightColumn);
            String leftColumn = GetTableNameFromClassSimpleName(StringUtil.GetLastUrl(serializedLambdaLeft.getImplClass())).toUpperCase()+"."+HumpTransform.humpToLine2(SerializedLambdaUtil.resolveFieldName(serializedLambdaLeft.getImplMethodName()));
            String rightColumn = GetTableNameFromClassSimpleName(StringUtil.GetLastUrl(serializedLambdaRight.getImplClass())).toUpperCase()+"."+HumpTransform.humpToLine2(SerializedLambdaUtil.resolveFieldName(serializedLambdaRight.getImplMethodName()));
            String tableAlias = GetTableNameFromClass(tableClass).toUpperCase();
            String condition =  leftColumn + "=" + rightColumn;
            joinTables.add(new JoinTable(subQueryCriteria, tableAlias, condition, joinType,tableClass,isResultTable,containPrefix));
            return this;
        }

        public<T1,T2> FromClause addJoinTableByClass(UnionCriteria subQueryCriteria,Class<?> tableClass, String condition, JoinType joinType) {
            if (subQueryCriteria == null || StringUtil.isEmpty(condition) || joinType == null) {
                return this;
            }
            String tableName = GetTableNameFromClass(tableClass).toUpperCase();
            String tableAlias = tableName;
            joinTables.add(new JoinTable(subQueryCriteria, tableAlias, condition, joinType));
            return this;
        }

        public FromClause addJoinTable(String tableName, String tableAlias, String condition, JoinType joinType,
                                       Class<?> tableClass) {
            if (StringUtil.isEmpty(tableName) || StringUtil.isEmpty(condition) || StringUtil.isEmpty(joinType)) {
                return this;
            }
            joinTables.add(new JoinTable(tableName, tableAlias, condition, joinType, tableClass));
            return this;
        }

        public FromClause addJoinTable(String tableName, String tableAlias, String condition, JoinType joinType) {
            if (StringUtil.isEmpty(tableName) || StringUtil.isEmpty(condition) || StringUtil.isEmpty(joinType)) {
                return this;
            }
            joinTables.add(new JoinTable(tableName, tableAlias, condition, joinType));
            return this;
        }

        public FromClause addJoinTable(String tableName, String condition, JoinType joinType) {
            if (StringUtil.isEmpty(tableName) || StringUtil.isEmpty(condition) || StringUtil.isEmpty(joinType)) {
                return this;
            }
            joinTables.add(new JoinTable(tableName, condition, joinType));
            return this;
        }

        public FromClause addJoinTable(UnionCriteria subQueryCriteria, String tableAlias, String condition, JoinType joinType,
                                       Class<?> tableClass) {
            if (subQueryCriteria == null || StringUtil.isEmpty(condition) || StringUtil.isEmpty(joinType)) {
                return this;
            }
            joinTables.add(new JoinTable(subQueryCriteria, tableAlias, condition, joinType, tableClass));
            return this;
        }

        public FromClause addJoinTable(UnionCriteria subQueryCriteria, String tableAlias, String condition, JoinType joinType) {
            if (subQueryCriteria == null || StringUtil.isEmpty(condition) || StringUtil.isEmpty(joinType)) {
                return this;
            }
            joinTables.add(new JoinTable(subQueryCriteria, tableAlias, condition, joinType));
            return this;
        }

        public FromClause addJoinTable(UnionCriteria subQueryCriteria, String condition, JoinType joinType) {
            if (subQueryCriteria == null || StringUtil.isEmpty(condition) || StringUtil.isEmpty(joinType)) {
                return this;
            }
            joinTables.add(new JoinTable(subQueryCriteria, condition, joinType));
            return this;
        }

        public List<JoinTable> getJoinTables() {
            return joinTables;
        }

        public void setJoinTables(List<JoinTable> joinTables) {
            this.joinTables = joinTables;
        }

        public String getMasterTable() {
            return masterTable;
        }

        public void setMasterTable(String masterTable) {
            this.masterTable = masterTable;
        }

        public String getMasterTableAlias() {
            return masterTableAlias;
        }

        public void setMasterTableAlias(String masterTableAlias) {
            this.masterTableAlias = masterTableAlias;
        }

    }

    public static class JoinTable {
        private String tableName;
        private String tableAlias;
        private String condition;
        private String joinType;
        private Class<?> tableClass;
        private UnionCriteria subQueryCriteria;
        private boolean isSubQuery = false;
        private boolean ContainPrefix=true;
        private boolean IsResultTable=true;



        public static Class<?> TableNameToClassBean(String tableName, String basePackage) {
            Class<?> c;
            String entityName;
            String realTableName = tableName;
            String shema = "";
            if (tableName.contains(".")) {
                String[] table = tableName.split("\\.");
                shema = table[0];
                realTableName = table[1];
                //String entitySimpleName = SequenceFormat.UnderlineToBeanHump(table[1]);
            }
            if (realTableName.startsWith(UnionCriteria.Table_Name_prefix)) {
                realTableName = realTableName.substring(UnionCriteria.Table_Name_prefix.length(), realTableName.length());
            }
            String entitySimpleName = HumpTransform.lineToHump(realTableName);
            entityName = basePackage + "." + shema.toLowerCase() + "." + entitySimpleName;
            try {
                c = Class.forName(entityName);
                return c;
            } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return null;
            }
        }

        public Class<?> getTableClass(String basePackage){
            Class<?> c;
            if (this.tableClass != null) {
                c = this.tableClass;

            } else {
                if (basePackage == null) {
                    return null;
                }

                String tableName = this.tableName;
                if (StringUtil.isEmpty(tableName)) {
                    return null;
                }
                c = TableNameToClassBean(tableName, basePackage);
            }
            return c;
        }

        public JoinTable(UnionCriteria subQueryCriteria, String tableAlias, String condition, JoinType joinType,Class<?> tableClass,boolean isResultTable, boolean containPrefix) {
            this.subQueryCriteria = subQueryCriteria;
            this.tableAlias = tableAlias;
            this.condition = condition;
            if (joinType == null) {
                this.joinType = "left join";
            } else {
                this.joinType = joinType.name;
            }
            this.tableClass = tableClass;
            this.isSubQuery = true;
            this.ContainPrefix=containPrefix;
            this.IsResultTable=isResultTable;
        }
        public JoinTable(UnionCriteria subQueryCriteria, String tableAlias, String condition, JoinType joinType,
                         Class<?> tableClass) {
            this(subQueryCriteria,tableAlias,condition,joinType,tableClass,true,true);
        }

        public JoinTable(UnionCriteria subQueryCriteria, String tableAlias, String condition, JoinType joinType) {
            this.subQueryCriteria = subQueryCriteria;
            this.tableAlias = tableAlias;
            this.condition = condition;
            if (joinType == null) {
                this.joinType = "left join";
            } else {
                this.joinType = joinType.name;
            }
            this.isSubQuery = true;
        }

        public JoinTable(UnionCriteria subQueryCriteria, String condition, JoinType joinType) {
            this(subQueryCriteria, null, condition, joinType);
        }
        public JoinTable(String tableName, String tableAlias, String condition, JoinType joinType, Class<?> tableClass,boolean isResultTable, boolean containPrefix) {
            this.tableName = tableName;
            this.tableAlias = tableAlias;
            this.condition = condition;
            if (joinType == null) {
                this.joinType = "left join";
            } else {
                this.joinType = joinType.name;
            }
            this.tableClass = tableClass;
            this.ContainPrefix=containPrefix;
            this.IsResultTable=isResultTable;
        }
        public JoinTable(String tableName, String tableAlias, String condition, JoinType joinType,
                         Class<?> tableClass) {
            this(tableName,tableAlias,condition,joinType,tableClass,true,true);
        }

        public JoinTable(String tableName, String tableAlias, String condition, JoinType joinType) {
            this.tableName = tableName;
            this.tableAlias = tableAlias;
            this.condition = condition;
            if (joinType == null) {
                this.joinType = "left join";
            } else {
                this.joinType = joinType.name;
            }
        }

        public JoinTable(String tableName, String condition, JoinType joinType) {
            this(tableName, null, condition, joinType);
        }

        public UnionCriteria getSubQueryCriteria() {
            return subQueryCriteria;
        }

        public void setSubQueryCriteria(UnionCriteria subQueryCriteria) {
            this.subQueryCriteria = subQueryCriteria;
        }

        public boolean isSubQuery() {
            return isSubQuery;
        }

        public void setSubQuery(boolean isSubQuery) {
            this.isSubQuery = isSubQuery;
        }


        public String getTableName() {
            return tableName;
        }

        public void setTableName(String tableName) {
            this.tableName = tableName;
        }

        public String getTableAlias() {
            return tableAlias;
        }

        public void setTableAlias(String tableAlias) {
            this.tableAlias = tableAlias;
        }

        public String getcondition() {
            return condition;
        }

        public void setcondition(String condition) {
            this.condition = condition;
        }

        public String getJoinType() {
            return joinType;
        }

        public void setJoinType(String joinType) {
            this.joinType = joinType;
        }

        public Class<?> getTableClass() {
            return tableClass;
        }

        public void setTableClass(Class<?> tableClass) {
            this.tableClass = tableClass;
        }

    }

    /*
     * public static enum JoinType { left("left"), right("right"), inner("inner"),
     * cross("cross"),full("full");
     *
     * JoinType(String value){ this.value=value; }
     *
     * private String value;
     *
     * public String getValue() { return value; }
     *
     * public void setValue(String value) { this.value = value; }
     *
     *
     * }
     */

    protected abstract static class GeneratedCriteria {
        protected List<Criterion> criteria;

        protected GeneratedCriteria() {
            super();
            criteria = new ArrayList<Criterion>();
        }

        public boolean isValid() {
            return criteria.size() > 0;
        }

        public List<Criterion> getAllCriteria() {
            return criteria;
        }

        public List<Criterion> getCriteria() {
            return criteria;
        }

        protected void addCriterion(String condition) {
            if (condition == null) {
                throw new RuntimeException("Value for condition cannot be null");
            }
            criteria.add(new Criterion(condition));
        }

        protected void addCriterion(String condition, Object value, String property) {
            if (value == null) {
                throw new RuntimeException("Value for " + property + " cannot be null");
            }
            criteria.add(new Criterion(condition, value));
        }

        protected void addCriterion(String condition, Object value1, Object value2, String property) {
            if (value1 == null || value2 == null) {
                throw new RuntimeException("Between values for " + property + " cannot be null");
            }
            criteria.add(new Criterion(condition, value1, value2));
        }

        public Criteria addCriterionSelective(String condition) {
            if (StringUtil.isEmpty(condition.trim())) {
                return (Criteria) this;
            }
            criteria.add(new Criterion(condition));
            return (Criteria) this;
        }
        public<T> Criteria addCriterionSelective(SFunction<T, ?> column,Object value,QueryTypeEnum queryTypeEnum) {
            if (StringUtil.isEmpty(value) ){
                return (Criteria) this;
            }
            java.lang.invoke.SerializedLambda serializedLambdaLeft=SerializedLambdaUtil.getSerializedLambda(column);
            String condition = GetTableNameFromClassSimpleName(StringUtil.GetLastUrl(serializedLambdaLeft.getImplClass())).toUpperCase()+"."+HumpTransform.humpToLine2(SerializedLambdaUtil.resolveFieldName(serializedLambdaLeft.getImplMethodName()));
            String queryType=GetConditionType(queryTypeEnum);
            criteria.add(new Criterion(condition+queryType,value));
            return (Criteria) this;
        }
        public<T> Criteria addCriterionSelective(SFunction<T, ?> column,Object value,Object value2,QueryTypeEnum queryTypeEnum) {
            if (StringUtil.isEmpty(value) ||StringUtil.isEmpty(value2)){
                return (Criteria) this;
            }
            java.lang.invoke.SerializedLambda serializedLambdaLeft=SerializedLambdaUtil.getSerializedLambda(column);
            String condition = GetTableNameFromClassSimpleName(StringUtil.GetLastUrl(serializedLambdaLeft.getImplClass())).toUpperCase()+"."+HumpTransform.humpToLine2(SerializedLambdaUtil.resolveFieldName(serializedLambdaLeft.getImplMethodName()));
            String queryType=GetConditionType(queryTypeEnum);
            criteria.add(new Criterion(condition+queryType,value,value2));
            return (Criteria) this;
        }

        public Criteria addCriterionSelective(String condition, Object value, String property) {
            if (StringUtil.isEmpty(value)) {
                return (Criteria) this;
            }
            criteria.add(new Criterion(condition, value));
            return (Criteria) this;
        }


        public Criteria addCriterionSelective(String condition, Object value1, Object value2, String property) {
            if (StringUtil.isEmpty(value1) || StringUtil.isEmpty(value2)) {
                return (Criteria) this;
            }
            criteria.add(new Criterion(condition, value1, value2));
            return (Criteria) this;
        }

    }

    public static class Criteria extends GeneratedCriteria {

        protected Criteria() {
            super();
        }
    }

    public static class Criterion {
        private String condition;

        private Object value;

        private Object secondValue;

        private boolean noValue;

        private boolean singleValue;

        private boolean betweenValue;

        private boolean listValue;

        private String typeHandler;

        public String getCondition() {
            return condition;
        }

        public Object getValue() {
            return value;
        }

        public Object getSecondValue() {
            return secondValue;
        }

        public boolean isNoValue() {
            return noValue;
        }

        public boolean isSingleValue() {
            return singleValue;
        }

        public boolean isBetweenValue() {
            return betweenValue;
        }

        public boolean isListValue() {
            return listValue;
        }

        public String getTypeHandler() {
            return typeHandler;
        }

        protected Criterion(String condition) {
            super();
            this.condition = condition;
            this.typeHandler = null;
            this.noValue = true;
        }

        protected Criterion(String condition, Object value, String typeHandler) {
            super();
            this.condition = condition;
            this.value = value;
            this.typeHandler = typeHandler;
            if (value instanceof List<?>) {
                this.listValue = true;
            } else {
                this.singleValue = true;
            }
        }

        protected Criterion(String condition, Object value) {
            this(condition, value, null);
        }

        protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
            super();
            this.condition = condition;
            this.value = value;
            this.secondValue = secondValue;
            this.typeHandler = typeHandler;
            this.betweenValue = true;
        }

        protected Criterion(String condition, Object value, Object secondValue) {
            this(condition, value, secondValue, null);
        }
    }
}